import asyncio
import websockets
import json
import base64
import wx
import wx._xml
import wx.adv
import wx.richtext
import wx.grid as gridlib
import threading
import requests
import queue
import shutil
import time
import os
import sys
import win32api
import win32con
from io import BytesIO
import socket
import subprocess
import psutil
import ctypes
import re
import datetime
import zipfile
import tarfile
import winreg
import argparse

import mimage
import config
import call
import mzjc



def handle_uncaught_exception(exc_type, exc_value, exc_traceback):
    """自定义的异常处理器"""
    #if issubclass(exc_type, KeyboardInterrupt):
    # 忽略Ctrl+C退出
    #    sys.__excepthook__(exc_type, exc_value, exc_traceback)
    #    return
    config.error_log("异常退出: {} {} {}".format(exc_type, exc_value, exc_traceback))


# 注册自定义的异常处理器
sys.excepthook = handle_uncaught_exception





# 设置文本颜色和背景颜色
def setprintcolor(FORE=config.FOREGROUND_GREEN, BACK=config.BACKGROUND_BLACK):
    ctypes.windll.kernel32.SetConsoleTextAttribute(config.HCONSOLE, FORE | BACK)


def initprint():
    ctypes.windll.kernel32.SetConsoleTextAttribute(config.HCONSOLE, 0x07)


#setprintcolor()
print("启动路径： ", config.START_EXE_PATH)





class FileDrop(wx.FileDropTarget):
    def __init__(self,windows):
        wx.FileDropTarget.__init__(self)
        self.windows = windows

    def OnDropFiles(self, x, y, filePath):
        if filePath:
            self.windows.SetValue(filePath[0])
            return True
        else:
            return False



class ButtonRenderer(gridlib.GridCellRenderer):
    def __init__(self, lable_id, value_label):
        super(ButtonRenderer, self).__init__()
        self.value_label = value_label
        self.lable_id = lable_id

    def Draw(self, grid, attr, dc, rect, row, col, isSelected):
        #btn_label = "绑定"  # 按钮文本
        dc.SetBackgroundMode(wx.SOLID)
        dc.SetPen(wx.Pen(wx.BLACK))
        dc.SetBrush(wx.Brush(wx.WHITE, wx.SOLID))
        dc.DrawRectangle(rect)
        dc.SetTextForeground(wx.BLUE)
        dc.DrawLabel(self.value_label, rect, wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL)

    def GetBestSize(self, grid, attr, dc, row, col):
        return wx.Size(60, 30)



# 系统托盘
class MyTaskBarIcon(wx.adv.TaskBarIcon):
    TITLE = '客户端'
    def __init__(self, frame):
        super().__init__()
        self.frame = frame
        by = BytesIO(mimage.image)
        p = wx.Image(by, type=wx.BITMAP_TYPE_ICO)
        by.close()
        wxico = wx.Icon()
        wxico.CopyFromBitmap(wx.Bitmap(p))
        self.SetIcon(wxico, self.TITLE)
        self.Bind(wx.adv.EVT_TASKBAR_LEFT_DOWN, self.on_left_down)
        self.Bind(wx.adv.EVT_TASKBAR_LEFT_DCLICK, self.on_left_dclick)

    def CreatePopupMenu(self):
        menu = wx.Menu()
        #newdata_item = menu.Append(wx.ID_ANY, "上传数据")
        update_item = menu.Append(wx.ID_ANY, "检查更新")
        menu.AppendSeparator()
        exit_item = menu.Append(wx.ID_ANY, "退出")
        restore_item = menu.Append(wx.ID_ANY, "重启")
        self.Bind(wx.EVT_MENU, self.on_restart, restore_item)
        self.Bind(wx.EVT_MENU, self.on_exit, exit_item)
        self.Bind(wx.EVT_MENU, self.on_update, update_item)
        return menu

    def on_left_down(self, event):
        if self.frame.IsIconized():
            self.frame.Iconize(False)
        self.frame.Raise()

    def on_left_dclick(self, event):
        self.frame.Iconize(False)
        self.frame.Show(True)

    def on_restart(self, event):
        if config.START_EXE_PATH.endswith(".py"):
            wx.MessageBox("py启动模式 禁止重启", "提示", wx.OK, self.frame)
            return
        answ = wx.MessageBox("是否重启", "提示", wx.YES_NO, self.frame)
        if answ == wx.YES:
            def on_exit(window):
                window.mop.stop()
                window.mop.join()
                os.execl(sys.executable, sys.executable)
                #try:
                #    if window.mws:
                #        window.mws._stop()
                #    if window.mth:
                #        window.mth._stop()
                #    window.mop.stop()
                #    window.mop.join()
                #    wx.CallAfter(window.on_restartApp, True)
                #except Exception as e:
                #    config.error_log(e)
            threading.Thread(target=on_exit, args=(self.frame,)).start()

    def on_update(self, event):
        if config.START_EXE_PATH.endswith(".py"):
            wx.MessageBox("py启动模式 禁止更新", "提示", wx.OK, self.frame)
            return
        self.frame.mth.my_call(call.Exe_Update)

    def on_exit(self, event):
        wx.CallAfter(self.frame.OnExit) 



class MyDialog(wx.Dialog):
    def __init__(self, parent, title, url):
        super(MyDialog, self).__init__(parent, title=title, size=(900, 120))
        self.window = parent
        # 创建一个输入框
        self.title = title
        self.text_ctrl = wx.TextCtrl(self, value=url)

        # 创建确定和取消按钮
        self.ok_button = wx.Button(self, label='更新', id=wx.ID_OK)
        self.cancel_button = wx.Button(self, label='取消', id=wx.ID_CANCEL)

        # 创建一个布局管理器
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizerh = wx.BoxSizer(wx.HORIZONTAL)
        sizerh.Add(self.ok_button, 1, wx.EXPAND | wx.ALL, 5)
        sizerh.Add(self.cancel_button, 1, wx.EXPAND | wx.ALL, 5)

        sizer.Add(self.text_ctrl, 0, wx.EXPAND | wx.ALL, 5)
        sizer.Add(sizerh, 0, wx.EXPAND | wx.ALL, 5)
        self.ok_button.Bind(wx.EVT_BUTTON, self.on_button)
        self.cancel_button.Bind(wx.EVT_BUTTON, self.on_close)
        self.SetSizer(sizer)
        self.Centre( wx.BOTH )
        self.Layout()

    def on_close(self, eve):
        self.Destroy()

    def on_button(self, eve):
        self.ok_button.Enable(False)
        self.window.window.mth.my_call(call.Exe_Update_gz, self, self.text_ctrl.GetValue(), self.title)


class add_MyDialog(wx.Dialog):
    def __init__(self, parent, title):
        super(add_MyDialog, self).__init__(parent, title=title, size=(500, 280))
        self.window = parent
        sizer = wx.BoxSizer(wx.VERTICAL)

        bSizer1 = wx.BoxSizer(wx.HORIZONTAL)
        self.exe_path = wx.TextCtrl(self, value="")
        self.exe_path.SetDropTarget(FileDrop(self.exe_path))
        self.file_button = wx.Button(self, label='选择文件')
        bSizer1.Add(wx.StaticText(self, label="程序路径:"), 0, wx.EXPAND | wx.ALL, 5 )
        bSizer1.Add(self.exe_path, 1, wx.EXPAND | wx.ALL, 5 )
        bSizer1.Add(self.file_button, 0, wx.EXPAND | wx.ALL, 5 )

        bSizer2 = wx.BoxSizer(wx.HORIZONTAL)
        self.update_url = wx.TextCtrl(self, value="")
        bSizer2.Add(wx.StaticText(self, label="更新地址:"), 0, wx.EXPAND | wx.ALL, 5 )
        bSizer2.Add(self.update_url, 1, wx.EXPAND | wx.ALL, 5 )

        bSizerargs = wx.BoxSizer(wx.HORIZONTAL)
        self.exe_cmd = wx.TextCtrl(self, value="")
        bSizerargs.Add(wx.StaticText(self, label="启动参数:"), 0, wx.EXPAND | wx.ALL, 5 )
        bSizerargs.Add(self.exe_cmd, 1, wx.EXPAND | wx.ALL, 5 )

        bSizer3 = wx.BoxSizer(wx.HORIZONTAL)
        self.exe_run = wx.CheckBox( self, -1, u"关联启动")
        bSizer3.Add(self.exe_run, 1, wx.EXPAND | wx.ALL, 5 )

        bSizer4 = wx.BoxSizer(wx.HORIZONTAL)
        self.ok_button = wx.Button(self, label='添加', id=wx.ID_OK)
        self.cancel_button = wx.Button(self, label='取消', id=wx.ID_CANCEL)
        bSizer4.Add(self.ok_button, 1, wx.EXPAND | wx.ALL, 5)
        bSizer4.Add(self.cancel_button, 1, wx.EXPAND | wx.ALL, 5)
        
        sizer.Add(bSizer1, 0, wx.EXPAND | wx.ALL, 5)
        sizer.Add(bSizer2, 0, wx.EXPAND | wx.ALL, 5)
        sizer.Add(bSizerargs, 0, wx.EXPAND | wx.ALL, 5)
        sizer.Add(bSizer3, 0, wx.EXPAND | wx.ALL, 5)
        sizer.Add(bSizer4, 0, wx.EXPAND | wx.ALL, 5)
        self.ok_button.Bind(wx.EVT_BUTTON, self.on_button)
        self.cancel_button.Bind(wx.EVT_BUTTON, self.on_close)
        self.file_button.Bind(wx.EVT_BUTTON, self.on_file)
        self.SetSizer(sizer)
        self.Centre( wx.BOTH )
        self.Layout()

    def on_file(self, eve):
        dlg = wx.FileDialog(
            self, message="选择程序",
            defaultDir=config.START_EXE_PATH,  # 可以设置默认目录
            wildcard="All files (*.exe)|*.exe",  # 文件过滤器
            style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST  # 设置打开文件，并且文件必须存在
        )
        dlg.SetDirectory(config.START_EXE_PATH)
        if dlg.ShowModal() == wx.ID_OK:
            filepath = dlg.GetPath()
            self.exe_path.SetValue(dlg.GetPath())
        dlg.Destroy()

    def on_close(self, eve):
        self.Destroy()

    def on_button(self, eve):
        self.ok_button.Enable(False)
        _url = self.update_url.GetValue()
        _path = self.exe_path.GetValue()
        
        if not re.match(r'https?://\S+', _url):
            wx.MessageBox("URL链接格式不正确", "提示", wx.OK, self)
            self.ok_button.Enable(True)
            return
        if not os.path.exists(_path):
            wx.MessageBox("程序路径不存在", "提示", wx.OK, self)
            self.ok_button.Enable(True)
            return
        if "\\" not in os.path.abspath(_path):
            wx.MessageBox("路径必须为绝对路径", "提示", wx.OK, self)
            self.ok_button.Enable(True)
            return
        if _path.split(".")[-1] != "exe":
            wx.MessageBox("不是EXE程序", "提示", wx.OK, self)
            self.ok_button.Enable(True)
            return
        dic={"path":_path,"status":self.exe_run.GetValue(),"url":_url}
        cmd = self.exe_cmd.GetValue()
        if cmd != "":
            cmd = self.is_valid_arguments(cmd)
            if not cmd:
                wx.MessageBox("启动参数填写错误", "提示", wx.OK, self)
                self.ok_button.Enable(True)
                return
            dic.update({"args": cmd})
        async def _button_call(window, selfs, dic):
            listcmd = window.cli._dict.get("listcmd", [])
            if dic["path"] in [ key["path"] for key in listcmd ]:
                wx.MessageBox(dic["path"] + "已存在", "提示", wx.OK, selfs)
                wx.CallAfter(selfs.ok_button.Enable, True)
                return
            listcmd.append(dic)
            window.cli.setIni("listcmd", listcmd)
            wx.CallAfter(selfs.window.add_model, dic)
            wx.CallAfter(selfs.on_close, None)
        self.window.window.mth.my_call(_button_call, self, dic)

    def is_valid_arguments(self, arg_string):
        # 将字符串按照空格分割成多个部分
        parts = arg_string.split()
        
        # 检查是否以 "--" 开头
        if not parts or not parts[0].startswith('--'):
            return False
        
        for i in range(0, len(parts), 2):
            # 检查每个参数是否以 "--" 开头
            if not parts[i].startswith('--'):
                return False
            
            # 检查是否有对应的值
            if i + 1 >= len(parts):
                return False
            
            # 检查参数名的有效性
            param_name = parts[i][2:]
            if not param_name.isidentifier():
                return False
            
            # 检查值的有效性（这里简单地检查非空即可，可以根据需求调整）
            param_value = parts[i + 1]
            if not param_value:
                return False
        return parts



class MyFrame4 ( wx.Frame ):
    def __init__( self, window ):
        super().__init__(None, title="手动绑定", size = wx.Size( 800, 500 ))
        self.window = window
        self.bind_data = self.window.cli._dict["bind"]["data"]
        self.bind_data_len = len(self.bind_data)
        self.wuserid = self.window.cli._dict["wuserid"]
        self.bindid = -1

        self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
        bSizer1 = wx.BoxSizer( wx.VERTICAL )
        self.m_button1 = wx.Button( self, wx.ID_ANY, u"刷新", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer1.Add(self.m_button1, 0, wx.EXPAND, 5 )

        bSizer2 = wx.BoxSizer( wx.HORIZONTAL )
        bSizer2.Add(wx.StaticText(self, label="绑定字段匹配:", style=wx.ALIGN_CENTER_VERTICAL), 0, wx.ALL, 5 )
        self.m_choice2 = wx.Choice( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, [k["name"] for k in self.bind_data], 0 )
        if self.bind_data_len < self.window.cli._dict["bindid"]:
            self.window.cli.setIni("bindid", 0)
        self.m_choice2.SetSelection( self.window.cli._dict["bindid"] )
        bSizer2.Add(self.m_choice2, 1, wx.EXPAND, 5 )
        bSizer1.Add(bSizer2, 0, wx.EXPAND|wx.ALL, 5 )

        self.grid = gridlib.Grid(self)
        self.grid.CreateGrid(0, 0)
        self.grid.EnableEditing(False)
        self.grid.SetCellHighlightPenWidth(0)
        self.grid.SetCellHighlightROPenWidth(0)
        self.grid.AppendCols(self.bind_data_len + 1)


        for index, key in enumerate(self.bind_data):
            self.grid.SetColLabelValue(index, key["name"])
        self.grid.SetColLabelValue(self.bind_data_len, "绑定按钮")
        bSizer1.Add(self.grid, 1, wx.EXPAND|wx.ALL, 5 )
        self.m_button1.Enable(False)

        self.SetSizer( bSizer1 )
        self.Centre( wx.BOTH )
        self.Layout()
        
        self.window.mth.my_call(call.InitData_init, self)
        self.m_button1.Bind(wx.EVT_BUTTON, self.on_click)
        self.m_choice2.Bind(wx.EVT_CHOICE, self.on_choice)
        self.Bind(gridlib.EVT_GRID_CELL_LEFT_CLICK, self.OnCellLeftClick)


    def addselect(self, dic):
        row_pos = self.grid.GetNumberRows()
        self.grid.InsertRows(row_pos)
        for index, key in enumerate(self.bind_data):
            self.grid.SetCellValue(row_pos, index, str(dic.get(key["value"], "")))
        value = "绑定"    
        if dic["_id"] == self.wuserid:
            value = "已绑定"
            self.bindid = row_pos
        self.grid.SetCellRenderer(row_pos, self.bind_data_len, ButtonRenderer(dic["_id"], value))

    def OnCellLeftClick(self, event):
        row = event.GetRow()
        col = event.GetCol()
        if col == self.bind_data_len:
            renderer = self.grid.GetCellRenderer(row, col)
            if self.bindid != -1:
                a = wx.MessageBox("你已绑定有数据，确定要重新绑定吗", "绑定提示", wx.YES_NO, self)
                if a == wx.NO:
                    return
            cell_value = self.grid.GetCellValue(row, self.m_choice2.GetSelection())
            if cell_value != "":
                a = wx.MessageBox("你要绑定的值已经有绑定对象了，确定强制绑定吗\n绑定对象: {} ".format(cell_value), "绑定提示", wx.YES_NO, self)
                if a == wx.NO:
                    return
            renderer.value_label = "已绑定"
            ipad_text = self.window.ipaddr_text.GetValue()
            name_text = self.window.nameid_text.GetValue()
            wx.CallAfter(self.window.userid_text.SetValue, renderer.lable_id)
            self.window.cli.setIni("wuserid", renderer.lable_id)
            self.window.mth.my_call(call.InitUser_call, ipad_text, name_text, renderer.lable_id)
            self.grid.GetCellRenderer(self.bindid, col).value_label = "绑定"
            self.grid.Refresh()
            self.bindid = row
            self.wuserid = renderer.lable_id
        event.Skip()

    def on_choice(self, eve):
        self.window.cli.setIni("bindid", self.m_choice2.GetSelection())
        eve.Skip()

    def on_click(self, eve):
        self.m_button1.Enable(False)
        if self.grid.GetNumberRows() > 0:
            self.grid.DeleteRows(0, self.grid.GetNumberRows())
        self.window.mth.my_call(call.InitData_init, self)



class MyFrame2 ( wx.Frame ):
    def __init__( self, window ):
        super().__init__(window, title="挂载任务", size = wx.Size( 580, 320 ), style=wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER | wx.MAXIMIZE_BOX))
        self.window = window
        self.layout_chcae = {}
        bSizer1 = wx.BoxSizer( wx.VERTICAL )
        self.append_button = wx.Button( self, -1, "添加挂载任务")

        self.bSizer = wx.BoxSizer( wx.VERTICAL )
        self.scroller = wx.ScrolledWindow(self)
        self.scroller.SetScrollRate(0, 30)
        self.boxV = wx.BoxSizer( wx.VERTICAL )
        self.scroller.SetSizer(self.bSizer)

        bSizer1.Add( self.scroller, 1, wx.EXPAND, 5 )
        bSizer1.Add( self.append_button, 0, wx.EXPAND|wx.ALL, 5 )

        self.SetSizer( bSizer1 )
        self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
        self.Centre( wx.BOTH )
        self.Layout()

        self.append_button.Bind(wx.EVT_BUTTON, self.on_append)

        self.on_create()

    def on_create(self):
        for key in self.window.cli._dict.get("listcmd", []):
            wx.CallAfter(self.add_model, key)

    def Enable_start(self, value):
        if value in self.layout_chcae:
            layout = self.layout_chcae[value]
            layout["stop"].Enable(True)
            layout["restart"].Enable(True)
            layout["start"].Enable(False)

    def Enable_stop(self, value):
        if value in self.layout_chcae:
            layout = self.layout_chcae[value]
            layout["stop"].Enable(True)
            layout["restart"].Enable(True)
            layout["start"].Enable(True)

    def del_model(self, value):
        if value in self.layout_chcae:
            layout = self.layout_chcae[value]
            self.bSizer.Detach(layout["layout"])
            layout["layout"].Clear(True)
            layout["layout"].Destroy()
            self.Layout()

    def add_model(self, dic):
        mkey = dic["path"]
        box_h = wx.BoxSizer( wx.HORIZONTAL )
        wxText = wx.TextCtrl( self.scroller, -1, os.path.basename(mkey), style=wx.TE_READONLY)
        button1 = wx.Button( self.scroller, -1, "运行")
        button2 = wx.Button( self.scroller, -1, "停止")
        button3 = wx.Button( self.scroller, -1, "重启")
        button4 = wx.Button( self.scroller, -1, "更新")
        button5 = wx.Button( self.scroller, -1, "删除")
        box_h.Add( wxText, 1, wx.ALL, 5 )
        box_h.Add( button1, 0, wx.ALL, 5 )
        box_h.Add( button2, 0, wx.ALL, 5 )
        box_h.Add( button3, 0, wx.ALL, 5 )
        box_h.Add( button4, 0, wx.ALL, 5 )
        box_h.Add( button5, 0, wx.ALL, 5 )
        if mkey in mzjc._cmdclass:
            button1.Enable(False)
        self.bSizer.Add(box_h, 0, wx.EXPAND|wx.ALL, 5 )
        self.layout_chcae.update({mkey:{"layout":box_h, "start":button1, "stop":button2, "restart":button3, "update":button4, "delete":button5, "dict": dic}})
        button1.Bind(wx.EVT_BUTTON, lambda evt, value=mkey :self.button_start(value))
        button2.Bind(wx.EVT_BUTTON, lambda evt, value=mkey :self.button_stop(value))
        button3.Bind(wx.EVT_BUTTON, lambda evt, value=mkey :self.button_restart(value))
        button4.Bind(wx.EVT_BUTTON, lambda evt, value=mkey : self.button_update(value))
        button5.Bind(wx.EVT_BUTTON, lambda evt, value=mkey :self.button_delete(value))
        wx.CallAfter(self.Layout)

    def button_start(self, mkey):
        layout = self.layout_chcae[mkey]
        layout["start"].Enable(False)
        async def _button_call(window, layout):
            dic = layout["dict"]
            _cmd = mzjc.CmdClass(window, dic["path"], dic.get("args", []))
            _cmd.start()
            key = {"object": _cmd, "path": dic["path"], "url": dic["url"], "status": dic["status"], "args": dic.get("args", [])}
            mzjc._cmdclass.update({dic["path"] : key})
            wx.CallAfter(layout["stop"].Enable, True)
            wx.CallAfter(layout["restart"].Enable, True)
        self.window.mth.my_call(_button_call, layout)

    def button_stop(self, mkey):
        layout = self.layout_chcae[mkey]
        layout["stop"].Enable(False)
        async def _button_call(window, layout, paths):
            key = mzjc._cmdclass.get(paths)
            if key:
                key["object"].stop()
                mzjc._cmdclass.pop(paths)
                wx.CallAfter(layout["start"].Enable, True)
            wx.CallAfter(layout["stop"].Enable, True)
            wx.CallAfter(layout["restart"].Enable, True)
        self.window.mth.my_call(_button_call, layout, mkey)

    def button_restart(self, mkey):
        layout = self.layout_chcae[mkey]
        layout["restart"].Enable(False)
        async def _button_call(window, layout):
            dic = layout["dict"]
            key = mzjc._cmdclass.get(dic["path"])
            if key:
                key["object"].stop()
            _cmd = mzjc.CmdClass(window, dic["path"], dic.get("args", []))
            _cmd.start()
            key = {"object": _cmd, "path": dic["path"], "url": dic["url"], "status": dic["status"], "args": dic.get("args", [])}
            mzjc._cmdclass.update({dic["path"] : key})
            wx.CallAfter(layout["start"].Enable, False)
            wx.CallAfter(layout["stop"].Enable, True)
            wx.CallAfter(layout["restart"].Enable, True)
        self.window.mth.my_call(_button_call, layout)

    def button_update(self, mkey):
        layout = self.layout_chcae[mkey]
        layout["update"].Enable(False)
        dialog = MyDialog(self, layout["dict"]["path"], layout["dict"]["url"])
        dialog.ShowModal()
        layout["update"].Enable(True)

    def button_delete(self, mkey):
        answ = wx.MessageBox("确定删除[{}]吗".format(mkey), "提示", wx.YES_NO, self)
        if answ == wx.YES:
            async def _button_call(window, selfs, paths):
                listcmd = window.cli._dict.get("listcmd", [])
                for val in listcmd[:]:
                    if val["path"] == paths:
                        listcmd.remove(val)
                window.cli.setIni("listcmd", listcmd)
                key = mzjc._cmdclass.get(paths)
                if key:
                    key["object"].stop()
                    mzjc._cmdclass.pop(paths)
                wx.CallAfter(selfs.del_model, paths)
            self.window.mth.my_call(_button_call, self, mkey)

    def on_append(self, eve):
        dialog = add_MyDialog(self, "添加页面")
        dialog.ShowModal()


# 主页面
class MyFrame1 ( wx.Frame ):
    EXE_PATH = os.path.dirname(config.START_EXE_PATH)
    def __init__( self, parent, cli):
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = "版本：" + config.VERSION, pos = wx.DefaultPosition, size = wx.Size( 800,400 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
        self.cli = cli
        if self.cli.root:
            self.SetTitle("版本：" + config.VERSION + " [管理员]")
        self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
        bSizer1 = wx.BoxSizer( wx.HORIZONTAL )
        self.m_richText1 = wx.richtext.RichTextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0|wx.VSCROLL|wx.HSCROLL|wx.NO_BORDER|wx.WANTS_CHARS )
        bSizer1.Add( self.m_richText1, 2, wx.EXPAND |wx.ALL, 5 )
        bSizer2 = wx.BoxSizer( wx.VERTICAL )
        bSizer3 = wx.BoxSizer( wx.HORIZONTAL )
        self.m_staticText1 = wx.StaticText( self, wx.ID_ANY, u"服务器地址", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer3.Add( self.m_staticText1, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
        self.ipaddr_text = wx.TextCtrl( self, wx.ID_ANY, self.cli._dict["ipaddr"], wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer3.Add( self.ipaddr_text, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
        bSizer2.Add( bSizer3, 1, wx.EXPAND, 5 )
        bSizer4 = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, ''), wx.VERTICAL)
        self.m_button_edit = wx.Button( self, wx.ID_ANY, u"编辑", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer4.Add( self.m_button_edit, 0, wx.EXPAND|wx.ALL, 5 )
        bSizer8 = wx.BoxSizer( wx.HORIZONTAL )
        self.m_staticText2 = wx.StaticText( self, wx.ID_ANY, u"表名ID", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer8.Add( self.m_staticText2, 0, wx.ALL, 5 )
        self.nameid_text = wx.ComboBox( self, wx.ID_ANY, self.cli._dict["wbookid"], choices=[])
        bSizer8.Add( self.nameid_text, 1, wx.ALL, 5 )
        self.m_button_init = wx.Button( self, wx.ID_ANY, u"获取", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer8.Add( self.m_button_init, 0, wx.ALL, 5 )
        bSizer4.Add( bSizer8, 0, wx.EXPAND, 5 )
        bSizer9 = wx.BoxSizer( wx.HORIZONTAL )
        self.m_staticText3 = wx.StaticText( self, wx.ID_ANY, u"数据ID", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer9.Add( self.m_staticText3, 0, wx.ALL, 5 )
        self.userid_text = wx.ComboBox( self, wx.ID_ANY, self.cli._dict["wuserid"], choices=[self.cli._dict["wuserid"], "自动添加绑定"])
        bSizer9.Add( self.userid_text, 1, wx.ALL, 5 )
        self.m_button_zdbind = wx.Button( self, wx.ID_ANY, u"绑定", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer9.Add( self.m_button_zdbind, 0, wx.ALL, 5 )
        bSizer4.Add( bSizer9, 0, wx.EXPAND, 5 )
        self.m_button_sdbind = wx.Button( self, wx.ID_ANY, u"手动绑定", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer4.Add( self.m_button_sdbind, 0, wx.EXPAND|wx.ALL, 5 )
        bSizer2.Add( bSizer4, 0, wx.EXPAND, 5 )
        bSizer7 = wx.BoxSizer( wx.VERTICAL )
        bSizer8 = wx.BoxSizer( wx.HORIZONTAL )
        
        self.startk_call = wx.CheckBox( self, wx.ID_ANY, u"数据转发", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer8.Add( self.startk_call, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
        self.m_button20 = wx.Button( self, wx.ID_ANY, u"挂载任务", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer8.Add( self.m_button20, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
        bSizer6 = wx.BoxSizer( wx.HORIZONTAL )
        self.startk_box = wx.CheckBox( self, wx.ID_ANY, u"开机自启", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer6.Add( self.startk_box, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
        self.m_button_stop = wx.Button( self, wx.ID_ANY, u"关闭连接", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer6.Add( self.m_button_stop, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
        self.m_button_start = wx.Button( self, wx.ID_ANY, u"启动连接", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer6.Add( self.m_button_start, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 )
        bSizer7.Add( bSizer8, 1, wx.EXPAND, 5 )
        bSizer7.Add( bSizer6, 1, wx.EXPAND, 5 )
        bSizer2.Add( bSizer7, 1, wx.EXPAND, 5 )
        bSizer1.Add( bSizer2, 1, wx.EXPAND, 5 )
        
        self.taskbar_icon = MyTaskBarIcon(self)
        self.startk_box.SetValue(self.cli._dict["statrun"])
        self.startk_call.SetValue(self.cli._dict["statcmd"])
        self.nameid_text.Enable(False)
        self.userid_text.Enable(False)
        self.m_richText1.SetEditable(False)

        self.SetSizer( bSizer1 )
        self.Centre( wx.BOTH )
        self.Layout()

        self.statcmd = self.cli._dict["statcmd"]
        self.mth = mzjc.pyqt_thread(self)
        self.mth.start()
        self.mop = mzjc.while_loop(self)
        self.mop.start()

        self.close_all_call = False
        self.gzframe = None
        self.mws = None
        if self.cli._dict["statrun"] == True:
            self.on_StartServer(0)
        if self.cli._dict["statcmd"] == True:
            self.mth.my_call(self.stat_all)

        # 将加速键表应用到窗口
        self.SetAcceleratorTable(wx.AcceleratorTable([(wx.ACCEL_CTRL, ord('Z'), wx.ID_EXIT)]))
        self.m_button_sdbind.Bind(wx.EVT_BUTTON, lambda evt, typ=1 : self.on_NewWindow(evt, typ)) # 手动绑定
        self.m_button20.Bind(wx.EVT_BUTTON, lambda evt, typ=2 : self.on_NewWindow(evt, typ)) # 挂载任务

        self.m_button_zdbind.Bind(wx.EVT_BUTTON, lambda evt, typ=1 : self.on_BindInit(evt, typ)) # 绑定
        self.nameid_text.Bind(wx.EVT_COMBOBOX, lambda evt, typ=2 : self.on_BindInit(evt, typ)) # 初始化
        self.m_button_init.Bind(wx.EVT_BUTTON, lambda evt, typ=3 : self.on_BindInit(evt, typ)) # 获取表名ID列表
        
        self.m_button_edit.Bind(wx.EVT_BUTTON, self.on_ButtonSetCtrl)
        self.startk_box.Bind(wx.EVT_CHECKBOX, lambda evt, typ=1 : self.on_StarRun(evt, typ))
        self.startk_call.Bind(wx.EVT_CHECKBOX, lambda evt, typ=2 : self.on_StarRun(evt, typ))
        self.m_button_start.Bind(wx.EVT_BUTTON, self.on_StartServer) # 启动连接
        self.m_button_stop.Bind(wx.EVT_BUTTON, self.on_CloseServer) # 关闭连接
        self.Bind(wx.EVT_MENU, self.ctrl_exit, id=wx.ID_EXIT)
        self.Bind(wx.EVT_CLOSE, self.on_close)

    def on_close(self, eve):
        ipaddr_text = self.ipaddr_text.GetValue()
        if self.cli._dict["ipaddr"] != ipaddr_text:
            self.cli.setIni("ipaddr", ipaddr_text)
        self.cli.setIni("statcmd", self.startk_call.GetValue())
        if self.IsIconized():
            self.Iconize(False)
        self.Show(False)

    def ctrl_exit(self, eve):
        answ = wx.MessageBox("强制退出吗", "提示", wx.YES_NO, self)
        if answ == wx.YES:
            startupinfo = subprocess.STARTUPINFO()
            startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
            startupinfo.wShowWindow = subprocess.SW_HIDE
            subprocess.Popen(['taskkill', '/F', '/T', '/PID', str(os.getpid())], startupinfo=startupinfo)

    def on_restartApp(self, isrun):
        try:
            self.mesage_add("关闭实例")
            self.taskbar_icon.Destroy()
            if self.gzframe:
                self.gzframe.Destroy()
            self.mesage_add("退出重启")
            self.Destroy()
            wx.Exit()
            if isrun:
                os.execl(sys.executable, sys.executable)
        except Exception as e:
            config.error_log(e)

    async def stat_all(self, window):
        for key in self.cli._dict["listcmd"]:
            if key["status"]:
                _cmd = mzjc.CmdClass(self, key["path"], key.get("args", []))
                _cmd.start()
                mzjc._cmdclass.update({key["path"] : {"object": _cmd, "path": key["path"], "url": key["url"], "status": key["status"], "args": key.get("args", [])}})
        
    def OnExit(self):
        answ = wx.MessageBox("是否退出", "提示", wx.YES_NO, self)
        if answ == wx.YES:
            self.close_all_call = True
            def on_exit(window):
                #config.error_log("手动退出")
                try:
                    wx.CallAfter(window.m_richText1.Clear)
                    wx.CallAfter(window.mesage_add, "关闭异步线程。。。")
                    window.mth._stop()
                    time.sleep(0.1)
                    wx.CallAfter(window.mesage_add, "异步线程已关闭。。。")
                    if window.mws:
                        wx.CallAfter(window.mesage_add, "关闭ws连接服务。。。")
                        window.mws.close()
                        if hasattr(window.mws.websocket, "closed"):
                            while not window.mws.websocket.closed:
                                time.sleep(0.01)
                        time.sleep(0.1)
                        window.mws._stop()
                        wx.CallAfter(window.mesage_add, "ws连接服务已关闭。。。") 
                    wx.CallAfter(window.mesage_add, "关闭挂载任务。。。") 
                    window.mop.stop()
                    window.mop.join()
                    wx.CallAfter(window.mesage_add, "挂载任务关闭完成。。。")
                    wx.CallAfter(window.on_restartApp, False)
                except Exception as e:
                    config.error_log(e)
            threading.Thread(target=on_exit, args=(self,)).start()

    def on_NewWindow(self, eve, typ):
        bind = self.cli._dict.get("bind")
        if not bind:
            self.mesage_add("表名ID未初始化")
            return
        if bind["apiid"] != self.nameid_text.GetValue():
            self.mesage_add("表名ID与初始化数据不相同同，请重新初始化")
            return
        if typ == 1:
            name_text = self.nameid_text.GetValue()
            if len(name_text) == 0 :
                self.mesage_add("表名ID未设置")
                return
            bind = self.cli._dict.get("bind")
            if not bind:
                self.mesage_add("表名ID未初始化")
                return
            if bind["apiid"] != name_text:
                self.mesage_add("表名ID与初始化数据不相同同，请重新初始化")
                return
            frame = MyFrame4(self)
            frame.Show()
        elif typ == 2:
            if not self.gzframe:
                self.gzframe = MyFrame2(self)
            if self.gzframe.IsIconized():
                self.gzframe.Iconize(False)  # 取消最小化
            self.gzframe.Show()  # 手动显示窗口
            self.gzframe.Raise() # 窗口置顶

    def on_CloseServer(self, eve):
        self.m_button_start.Enable(True)
        self.m_button_stop.Enable(False)
        self.m_button_sdbind.Enable(True)
        self.m_button_zdbind.Enable(True)
        self.mws.close()

    def on_StartServer(self, eve):
        self.m_button_edit.SetLabel("编辑")
        self.m_button_sdbind.Enable(False)
        self.m_button_zdbind.Enable(False)
        self.userid_text.Enable(False)
        self.nameid_text.Enable(False)
        self.m_button_start.Enable(False)
        self.mth.my_call(self.connect_wsbsock, 0)

    def on_StarRun(self, eve, typ):
        if typ == 1:
            starcall = self.startk_box.GetValue()
            if self.cli._dict["statrun"] != starcall:
                self.cli.setIni("statrun", starcall)
            self.mth.my_call(call.addfile2autorun, starcall, config.START_EXE_PATH)
        else:
            self.statcmd = self.startk_call.GetValue()
            self.cli._dict["statcmd"] = self.startk_call.GetValue()
            self.cli.setIni("statcmd", self.startk_call.GetValue())

    def on_ButtonSetCtrl(self, eve):
        if self.m_button_edit.GetLabel() == "编辑":
            self.m_button_sdbind.Enable(True)
            self.m_button_zdbind.Enable(True)
            self.userid_text.Enable(True)
            self.nameid_text.Enable(True)
            self.m_button_edit.SetLabel("完成")
        else:
            self.m_button_sdbind.Enable(False)
            self.m_button_zdbind.Enable(False)
            self.userid_text.Enable(False)
            self.nameid_text.Enable(False)
            self.m_button_edit.SetLabel("编辑")

    def on_BindInit(self, eve, typ):
        ipad_text = self.ipaddr_text.GetValue()
        name_text = self.nameid_text.GetValue()
        user_text = self.userid_text.GetValue()
        if len(name_text) == 0 :
            self.mesage_add("表名ID未设置")
            return
        if typ == 1:
            bind = self.cli._dict.get("bind")
            if not bind:
                self.mesage_add("表名ID未初始化")
                return
            if bind["apiid"] != name_text:
                self.mesage_add("表名ID与初始化数据不相同同，请重新初始化")
                return
            if user_text == "自动添加绑定":
                user_text = ""
            self.mth.my_call(call.InitUser_call, ipad_text, name_text, user_text)
        elif typ == 2:
            self.cli.setIni("ipaddr", ipad_text)
            self.cli.setIni("wbookid", name_text)
            self.mth.my_call(call.InitDate_call, ipad_text, name_text)
        elif typ == 3:
            self.mth.my_call(call.InitGetDate, ipad_text)

    async def connect_wsbsock(self, parent, msleep):
        for k in range(0, msleep*10):
            if parent.m_button_start.IsEnabled() or parent.close_all_call:
                wx.CallAfter(parent.mesage_add, "已主动关闭连接")
                return 
            time.sleep(0.1)
        ipaddr = parent.ipaddr_text.GetValue()
        userid = parent.userid_text.GetValue()
        if ipaddr == "" or userid == "":
            wx.CallAfter(parent.mesage_add, "没有绑定数据ID")
            wx.CallAfter(parent.m_button_start.Enable, True)
            #wx.CallAfter(parent.m_button_stop.Enable, False)
            return
        if parent.mws and not parent.mws.websocket.closed:
            wx.CallAfter(parent.mesage_add, "已经启动了链接")
            wx.CallAfter(parent.m_button_stop.Enable, True)
            return
        if not parent.mws:
            parent.mws = mzjc.Wsclient(parent)
            parent.mws.start()
        else:
            parent.mws.ipaddr = ipaddr
            parent.mws.userid = userid
            parent.mws.run_websockets()

    def mesage_add(self, data):
        current_datetime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        self.m_richText1.AppendText(current_datetime + " " + data + "\n")
        self.m_richText1.SetInsertionPointEnd()
        self.m_richText1.ShowPosition(self.m_richText1.GetLastPosition())

        num_lines = self.m_richText1.GetNumberOfLines()
        if num_lines > 300:
            line_start = self.m_richText1.XYToPosition(0, num_lines-50)
            self.m_richText1.PositionToXY(line_start)
            self.m_richText1.SetEditable(True)
            self.m_richText1.Remove(0, line_start)
            self.m_richText1.SetEditable(False)




if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='集成连接器')
    parser.add_argument('--root', type=bool, default=False, help='提升权限运行')
    parser.add_argument('--uac', type=bool, default=False, help='提升权限运行')
    known_args, unknown_args = parser.parse_known_args()
    if known_args.root:
        call.uac_start_app(config.START_EXE_PATH)
    else:
        subprocess.Popen(
            [os.path.join(getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__))), "TrayIconBuster.exe")], 
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            shell=True) # 启动先清理残留图标
        cli = config.Config()
        setattr(cli, "root", known_args.uac)
        app = wx.App()
        locale = wx.Locale(wx.LANGUAGE_CHINESE_SIMPLIFIED)
        MyFrame1(None, cli).Show(False)
        app.MainLoop()


